home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BG_SRC.ZIP / BG_GRAF1.C < prev    next >
C/C++ Source or Header  |  1993-12-31  |  17KB  |  489 lines

  1. /*
  2.  *
  3.  *                     B  G  _  G  R  A  F  1  .  C
  4.  *         A graphics module for the backgammon playing program BG.C.
  5.  * This version  30th January 1993
  6.  *
  7.  *
  8.  
  9. +--------------------+--------+   Here is the screen layout.
  10. |                    | dice   |
  11. |                    |   area |
  12. |     board          +--------+   The dice area must always
  13. |                    | face   |   have a 2-1 aspect ratio, and the
  14. |     area           |   area |   text area must always have SIDE_ROWS
  15. |                    +--------+   and SIDE_COLS. The logo area is
  16. |                    |        |   a buffer zone. The help area holds
  17. |                    | text   |   one line of text.
  18. +--------------------+   area |
  19. |  help   area       |        |
  20. +--------------------+--------+   The board area is
  21. further divided into a grid of 14 by 12, which is used as the basis for
  22. drawing the points and the pieces, see BG_GRAF2.C.
  23.  
  24. *****************************************************************************/
  25.  
  26. #include "comp.h"
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <bios.h>
  30. #include <conio.h>
  31. #include <math.h>
  32. #include "bg.h"
  33.  
  34. /****************************************************************************/
  35. /* Local defines ... */
  36.  
  37. Disp_Cfg_t Disp_Cfg ;  /* How the hardware has come to me */
  38.  
  39. Screen_Const_t Grafs ; /* How I have divided the screen areas */
  40.  
  41. /* Here is the dice graphics structure */
  42. static struct {
  43.     short Area_Wide ;    /* Pixel sizeof entire... */
  44.     short Area_High ;    /* ...area, inclusive */
  45.     short Wide,High ;    /* Actual size of a single dice */
  46.     short Dot_Wide ;     /* Size of a dot... */
  47.     short Dot_High ;     /* ...on a face     */
  48.     short Dice1_X,Dice2_X ;   /* X position of the two die */
  49.     short X,Y ;          /* Absoulte screen position of dice area */
  50.     short T_Row,T_Col ;  /* A row of text below the dice, defined on the
  51.                             text grid, to show dice as a row of numbers */
  52. } Dice_Gr ;
  53.  
  54. boolean Force_BW = FALSE ; /* Force a black&white display from command line */
  55.  
  56. /****************************************************************************/
  57. /**** LOCAL PRIVATE FUNCTIONS ****/
  58.  
  59. static void Init_Text_Fields (void) ;
  60. static void Init_Dice_Grafs (void) ;
  61.  
  62. /****************************************************************************/
  63.  
  64. void Init_Graphics (void)
  65. /*
  66. PURPOSE: To initialise the screen to graphics mode and to set up
  67.          the various graphics structures used throughout the
  68.          program
  69. */
  70. {
  71.     {
  72.         #define CGATEST 0
  73.         #define EGATEST 0
  74.         #define IBMTEST 0
  75.         int G_Driver,G_Mode,G_Error ;
  76.         #if CGATEST
  77.         G_Driver = CGA ;
  78.         G_Mode   = CGAHI ;
  79.         printf ("\nWARNING: CGATEST:") ; (void)getch () ;
  80.         #elif EGATEST
  81.         G_Driver = EGA ;
  82.         G_Mode   = EGAHI ;
  83.         printf ("\nWARNING: EGATEST:") ; (void)getch () ;
  84.         #elif IBMTEST
  85.         G_Driver = IBM8514 ;
  86.         G_Mode   = 0 ;
  87.         printf ("\nWARNING: IBMTEST:") ; (void)getch () ;
  88.         #else
  89.         G_Driver = DETECT ;
  90.         #endif
  91.  
  92.         initgraph (&G_Driver,&G_Mode,"C:\\BORLANDC\\BGI") ;
  93.  
  94.         G_Error = graphresult () ;
  95.         if (G_Error != grOk) {
  96.             printf ("\nError %s",grapherrormsg(G_Error));
  97.             (void)getch () ;
  98.             exit (1) ;
  99.         } else if (G_Driver == CGA) {
  100.             closegraph () ;
  101.             printf ("\nERROR: This program requires an EGA or a VGA display.") ;
  102.             exit (1) ;
  103.         }
  104.         Disp_Cfg.Colour = TRUE ;
  105.         switch (G_Driver) {
  106.             case HERCMONOHI :
  107.             case EGAMONO :
  108.                 Disp_Cfg.Colour = FALSE ;
  109.                 break ;
  110.             case VGA:
  111.                 setgraphmode (VGAMED) ;
  112.                 break ;
  113.             case IBM8514:
  114.                 setgraphmode (0) ;
  115.                 break ;
  116.         }
  117.         if (Force_BW) {
  118.             Disp_Cfg.Colour = FALSE ;
  119.         }
  120.     }
  121.  
  122.     Get_Display_Config (&Disp_Cfg) ;
  123.     Init_Text_Fields () ;  /* The other fields made to fit with text */
  124.  
  125.     Grafs.Dice_Area_Y  = 1 ;
  126.     Grafs.Dice_Area_X  = Grafs.Text_X ;
  127.  
  128.     Init_Dice_Grafs () ;
  129.     Init_And_Draw_Logo () ;
  130.  
  131.     Grafs.Board_X    = 1 ;
  132.     Grafs.Board_Y    = 1 ;
  133.     Grafs.Board_Wide = Disp_Cfg.X_Pixels - Grafs.Text_Wide - (2*Disp_Cfg.Char_Wide) ;
  134.     Grafs.Board_High = Disp_Cfg.Y_Pixels - (Disp_Cfg.Char_High*2) - 2 ;
  135.     Grafs.Help_Y     = Grafs.Board_High ;
  136.  
  137.     Grafs.Grid_Wide  = Grafs.Board_Wide / GRID_COLS ;
  138.     Grafs.Grid_High  = Grafs.Board_High / GRID_ROWS ;
  139.  
  140.     Grafs.Board_Wide = GRID_COLS * Grafs.Grid_Wide ; /* Now they are ...    */
  141.     Grafs.Board_High = GRID_ROWS * Grafs.Grid_High ; /* ...exact multiples. */
  142.  
  143.     Grafs.Unit_Wide  = Grafs.Grid_Wide-4 ;
  144.     Grafs.Unit_High  = Grafs.Grid_High-4 ;
  145.  
  146.     Get_Grid_Corner (&Grafs.Double_X,&Grafs.Double_Y,BAR_COL,DOUBLE_ROW) ;
  147. }
  148.  
  149. /****************************************************************************/
  150.  
  151. static void Init_Text_Fields (void)
  152. /*
  153. PURPOSE: To initialise the text fields so that there is a block of text
  154. to the left-bottom of TEXT_ROWS high and TEXT_COLS wide. We also init
  155. the help text area so that there is a single row of text available.
  156. The positions are based on a character sized matrix over the whole screen
  157. because some compilers and or devices cannot put text at abitrary x-y
  158. positions.
  159. */
  160. {
  161.     Grafs.Text_Wide  = SIDE_COLS*Disp_Cfg.Char_Wide ;
  162.     Grafs.Text_High  = SIDE_ROWS*Disp_Cfg.Char_High ;
  163.     Grafs.Text_X     = Disp_Cfg.X_Pixels - Grafs.Text_Wide ;
  164.     Grafs.Text_Y     = Disp_Cfg.Y_Pixels - Grafs.Text_High ;
  165.     Grafs.Help_X     = 0 ;
  166.     Grafs.Help_Y     = (Disp_Cfg.Y_Pixels/Disp_Cfg.Char_High) * Disp_Cfg.Char_High  ;
  167.     Grafs.Help_Wide  = Disp_Cfg.X_Pixels - Grafs.Text_Wide ;
  168.     Grafs.Help_Cols  = Disp_Cfg.Text_Cols - SIDE_COLS ;
  169. }
  170.  
  171. /****************************************************************************/
  172.  
  173. void Get_Grid_Corner (short* Grid_X,  short* Grid_Y,
  174.                       short Grid_Col, short Grid_Row)
  175. /*
  176. PURPOSE: To return in Grid_X, Grid_Y the absolute coords of the
  177.          top left of the Grid_Row,Grid_Col square.
  178. */
  179. {
  180.     (*Grid_X) = Grafs.Board_X + ((Grid_Col*Grafs.Board_Wide)/GRID_COLS) ;
  181.     (*Grid_Y) = Grafs.Board_Y + ((Grid_Row*Grafs.Board_High)/GRID_ROWS) ;
  182. }
  183.  
  184. /**************************************************************************/
  185.  
  186. void Get_Grid_Center (short* Grid_X,  short* Grid_Y,
  187.                       short Grid_Col, short Grid_Row)
  188. /*
  189. PURPOSE: To return in Grid_X, Grid_Y the absolute coords of the
  190.          middle of the Grid_Row,Grid_Col square.
  191. */
  192. {
  193.     Get_Grid_Corner (Grid_X,Grid_Y,Grid_Col,Grid_Row) ;
  194.     (*Grid_X) = (*Grid_X) + (Grafs.Grid_Wide/2) ;
  195.     (*Grid_Y) = (*Grid_Y) + (Grafs.Grid_High/2) ;
  196. }
  197.  
  198. /**************************************************************************/
  199.  
  200. void Draw_Dice_Pair (Dice_t* Pair, Player_t Player)
  201. /*
  202. PURPOSE: To show the two dice with the two values.
  203. */
  204. {
  205.     Draw_Die (Pair->Values[0],1,Player) ;
  206.     Draw_Die (Pair->Values[1],2,Player) ;
  207. }
  208.  
  209. /**************************************************************************/
  210.  
  211. /* The following array is initialised to the positions of dots for the
  212. 6 values of the dice faces when the face is divided into a 10 by 10 grid */
  213. static short Dot_Pos_Arr [7][6][2] =
  214.     {{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},   /* Value0 has no face */
  215.      {{5,5},{0,0},{0,0},{0,0},{0,0},{0,0}},   /* Single dot in centre */
  216.      {{2,5},{8,5},{0,0},{0,0},{0,0},{0,0}},   /* Two dots */
  217.      {{2,5},{8,5},{5,5},{0,0},{0,0},{0,0}},   /* Three dots */
  218.      {{2,2},{8,8},{2,8},{8,2},{0,0},{0,0}},   /* Four dots */
  219.      {{2,2},{8,8},{2,8},{8,2},{5,5},{0,0}},   /* Five dots */
  220.      {{2,2},{5,2},{8,2},{2,8},{5,8},{8,8}}};  /* Five dots */
  221. /* Later these values will be recalculated to make them the top left
  222. corner of the dots. */
  223.  
  224. static void Init_Dice_Grafs (void)
  225. /*
  226. PURPOSE: To set up the dice graphic variables.
  227. NOTES  : 1) The basic area is derived starting from Text_Wide.
  228.          2) The two dice are arranged as a horizontal pair, with
  229.             separated one from the other by 2 DICE_MARGINS and
  230.             from the edge of the area by a single DICE_MARGIN.
  231. */
  232. {
  233.     #define DICE_MARGIN 4
  234.     short y,v,dot ;
  235.     Dice_Gr.Area_Wide = Grafs.Text_Wide ;
  236.     Dice_Gr.X         = Grafs.Text_X ;
  237.     Dice_Gr.Wide      = (Dice_Gr.Area_Wide - (4*DICE_MARGIN)) / 2 ;
  238.     Dice_Gr.High      = (Dice_Gr.Wide * Disp_Cfg.Aspect_V) / Disp_Cfg.Aspect_H ;
  239.     Dice_Gr.Area_High = Dice_Gr.High +
  240.                          ((2*(DICE_MARGIN*Disp_Cfg.Aspect_V))/Disp_Cfg.Aspect_H) ;
  241.  
  242.     y = Dice_Gr.Area_High + (2*Disp_Cfg.Char_High) ;
  243.     Dice_Gr.T_Row = (y / Disp_Cfg.Char_High) - 1 ;
  244.     Dice_Gr.Area_High = Dice_Gr.Area_High + (2*Disp_Cfg.Char_High) ;
  245.  
  246.     Dice_Gr.T_Col = Disp_Cfg.Text_Cols - SIDE_COLS ;
  247.  
  248.     Dice_Gr.Dice1_X   = Grafs.Dice_Area_X + DICE_MARGIN ;
  249.     Dice_Gr.Dice2_X   = Grafs.Dice_Area_X + (3*DICE_MARGIN) + Dice_Gr.Wide ;
  250.     Dice_Gr.Y         = Grafs.Dice_Area_Y +
  251.                          ((DICE_MARGIN*Disp_Cfg.Aspect_V)/Disp_Cfg.Aspect_H) ;
  252.     Dice_Gr.Dot_Wide  = Dice_Gr.Wide / 5 ;
  253.     Dice_Gr.Dot_High  = Dice_Gr.High / 5 ;
  254.  
  255.     /* Setup positions for drawing dots */
  256.     for (v = 1 ; v <= 6 ; v++) {
  257.         for (dot = 0 ; dot < 6 ; dot++) {
  258.             Dot_Pos_Arr[v][dot][XI] = (Dot_Pos_Arr[v][dot][XI]*Dice_Gr.Wide)/10 ;
  259.             Dot_Pos_Arr[v][dot][XI] = Dot_Pos_Arr[v][dot][XI] -
  260.                                          (Dice_Gr.Dot_Wide/2) ;
  261.             Dot_Pos_Arr[v][dot][YI] = (Dot_Pos_Arr[v][dot][YI]*Dice_Gr.High)/10 ;
  262.             Dot_Pos_Arr[v][dot][YI] = Dot_Pos_Arr[v][dot][YI] -
  263.                                          (Dice_Gr.Dot_High/2);
  264.         }
  265.     }
  266. }
  267.  
  268. /****************************************************************************/
  269.  
  270. void Draw_Die (short Value, short Dice_Num, Player_t Player)
  271. /*
  272. PURPOSE: To draw a single die of Value. X_Pos is determined by Dice_Num
  273.          which should be 1 or 2.
  274. */
  275. {
  276.     short dot,Fill_Color,Dot_Color,X_Pos ;
  277.  
  278.     if ((Value < 1) || (Value > 6)) {
  279.         printf ("\nBad value in Draw_Die (%d,%d,%d)",Value,Dice_Num,Player) ;
  280.         Error_Exit ("\nBad Value in Draw_Die") ;
  281.     }
  282.  
  283.     if (Disp_Cfg.Colour) {
  284.         if (Player == BLACK_PLAYER) {
  285.             Fill_Color = LIGHTRED ;
  286.             Dot_Color  = WHITE ;
  287.         } else {
  288.             Fill_Color = WHITE ;
  289.             Dot_Color  = RED ;
  290.         }
  291.     } else {
  292.         if (Player == BLACK_PLAYER) {
  293.             Fill_Color = BLACK ;
  294.             Dot_Color  = WHITE ;
  295.         } else {
  296.             Fill_Color = WHITE ;
  297.             Dot_Color  = BLACK ;
  298.         }
  299.     }
  300.     if (Dice_Num == 1) {
  301.         X_Pos = Dice_Gr.Dice1_X ;
  302.     } else {
  303.         X_Pos = Dice_Gr.Dice2_X ;
  304.     }
  305.  
  306.     Fill_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High,Fill_Color) ;
  307.     Draw_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High,WHITE) ;
  308.  
  309.     /* draw the dots... */
  310.     for (dot = 0 ; dot < Value ; dot++) {
  311.         Fill_Rect (X_Pos     + Dot_Pos_Arr [Value][dot][XI],
  312.                    Dice_Gr.Y + Dot_Pos_Arr [Value][dot][YI],
  313.                    Dice_Gr.Dot_Wide,Dice_Gr.Dot_High,Dot_Color) ;
  314.     }
  315. }
  316.  
  317. /**************************************************************************/
  318.  
  319. void Clear_Die (short Dice_Num)
  320. /*
  321. PURPOSE: To clear the area of a single die of X_Pos is determined
  322.          by Dice_Num which should be 1 or 2.
  323. */
  324. {
  325.     short X_Pos ;
  326.  
  327.     if (Dice_Num == 1) {
  328.         X_Pos = Dice_Gr.Dice1_X ;
  329.     } else {
  330.         X_Pos = Dice_Gr.Dice2_X ;
  331.     }
  332.  
  333.     Fill_Rect (X_Pos,Dice_Gr.Y,Dice_Gr.Wide,Dice_Gr.High+1,BLACK) ;
  334. }
  335.  
  336. /**************************************************************************/
  337.  
  338. void Draw_Stats (void)
  339. /*
  340. PURPOSE: To draw the current statistics in the statistics box
  341. */
  342. {
  343.     extern Stats_t Statistics[2] ;
  344.     extern int Target_Score ;
  345.     short p ;
  346.  
  347.     Print_Message (ID_MSG) ;
  348.     Print_Message (TOTAL_MSG) ;
  349.     Print_Message (DOUBLE_MSG) ;
  350.     Print_Message (POINTS_MSG) ;
  351.  
  352.     for (p = BLACK_PLAYER ; p < N_PLAYERS ; p++) {
  353.         Side_Number (TOTALN_ROW, (ushort)(p*NUM_WIDE),
  354.                      Statistics[p].Total,NUM_WIDE,15) ;
  355.         Side_Number (DOUBN_ROW,  (ushort)(p*NUM_WIDE),
  356.                      Statistics[p].Doubles,NUM_WIDE,15) ;
  357.         Side_Number (POINTSN_ROW, (ushort)(p*NUM_WIDE),
  358.                      Statistics[p].Games_Won,NUM_WIDE,15) ;
  359.         Print_Message (PLAY_TO_MSG) ;
  360.         Side_Number (TARGETN_ROW,(ushort)(p*NUM_WIDE),
  361.                      Target_Score,NUM_WIDE,15) ;
  362.     }
  363. }
  364.  
  365. /**************************************************************************/
  366.  
  367. void Graf_Number (ushort Row, ushort Col, ushort Number,
  368.                   ushort F_Size, ushort Color)
  369. /*
  370. PURPOSE: To print the number at the Row,Col on the graphics screen.
  371. */
  372. {
  373.     char Num_Str [16] ;
  374.     ushort c ;
  375.  
  376.     /* Blank area for string */
  377.     for (c = 0 ; c < F_Size ; c++) {
  378.         Graf_Text (Row,Col+c," ",Color) ;
  379.     }
  380.  
  381.     (void)itoa (Number,Num_Str,10) ;
  382.     Graf_Text (Row,Col,Num_Str,Color) ;
  383. }
  384.  
  385. /**************************************************************************/
  386.  
  387. void Side_Number (ushort Row, ushort Col, ushort Number,
  388.                   ushort F_Size, ushort Color)
  389. /*
  390. PURPOSE: To print the number at the Row,Col of the side text in the
  391.          specified field size and color.
  392. */
  393. {
  394.     char Num_Str [16] ;
  395.     ushort c ;
  396.  
  397.     /* Blank area for string */
  398.     for (c = 0 ; c < F_Size ; c++) {
  399.         Side_Text (Row,Col+c," ",Color) ;
  400.     }
  401.  
  402.     (void)itoa (Number,Num_Str,10) ;
  403.     Side_Text (Row,Col,Num_Str,Color) ;
  404. }
  405.  
  406. /**************************************************************************/
  407.  
  408. void Init_And_Draw_Logo (void)
  409. /*
  410. PURPOSE: To draw the largest logo in the center of the space left for
  411.          that purpose. The space is what remains after the text and
  412.          dice areas have been initialised.
  413. */
  414. {
  415.     short Wide,High ;
  416.  
  417.     /* Initialise the fields telling us the area available */
  418.     Grafs.Logo_Y     = Dice_Gr.Area_High + 2 ; /* 2 dividing lines */
  419.     Grafs.Logo_X     = Grafs.Text_X ;
  420.     Grafs.Logo_High  = Disp_Cfg.Y_Pixels - Dice_Gr.Area_High -
  421.                          Grafs.Text_High - 4 ; /* 4 dividing lines */
  422.     if (Grafs.Logo_High <= 5) {
  423.         printf ("\nGrafs.Logo_High too small: %d.",Grafs.Logo_High) ;
  424.         Error_Exit ("Logo_High too small") ;
  425.     }
  426.     Grafs.Logo_Wide  = Grafs.Text_Wide ;
  427.  
  428.     if (Grafs.Logo_Wide > ((Grafs.Logo_High*Disp_Cfg.Aspect_H)/Disp_Cfg.Aspect_V)) {
  429.         /* Area is wider than high, logo square based on height */
  430.         High = Grafs.Logo_High-2 ;
  431.         Wide = (High*Disp_Cfg.Aspect_H)/Disp_Cfg.Aspect_V ;
  432.     } else {
  433.         /* Area is higher than wide, logo square based on width */
  434.         Wide = Grafs.Logo_Wide-2 ;
  435.         High = (Grafs.Logo_Wide*Disp_Cfg.Aspect_V)/Disp_Cfg.Aspect_H ;
  436.     }
  437.     /* Now Wide and High should draw a square on the screen */
  438.  
  439.     Grafs.Logo_X = ((Grafs.Logo_Wide - Wide) / 2) + Grafs.Logo_X + 1 ;
  440.     Grafs.Logo_Y = ((Grafs.Logo_High - High) / 2) + Grafs.Logo_Y + 1;
  441.     Grafs.Logo_Wide = Wide ;
  442.     Grafs.Logo_High = High ;
  443.     Grafs.Logo_Center = Grafs.Logo_X + (Grafs.Logo_Wide/2) ;
  444. }
  445.  
  446. /**************************************************************************/
  447.  
  448. void Clear_Logo_Area (void)
  449. /*
  450. PURPOSE: To clear the logo area to black.
  451. */
  452. {
  453.     Fill_Rect (Grafs.Logo_X,Grafs.Logo_Y,
  454.                Grafs.Logo_Wide,Grafs.Logo_High,BLACK) ;
  455. }
  456.  
  457. /**************************************************************************/
  458.  
  459. boolean Even (short Number)
  460. {
  461.     if (((Number/2)*2) == Number) {
  462.         return (TRUE) ;
  463.     } else {
  464.         return (FALSE) ;
  465.     }
  466. }
  467.  
  468. /**************************************************************************/
  469.  
  470. void Show_Dice_List (Dice_t* Dice)
  471. /*
  472. PURPOSE: To list the dice (0..4) as some digits below the drawing of the
  473. dice.
  474. */
  475. {
  476.     short i ;
  477.  
  478.     for (i = 0 ; i < SIDE_COLS ; i++ ) {
  479.         Graf_Text (Dice_Gr.T_Row, Dice_Gr.T_Col+i,"-",WHITE) ;
  480.     }
  481.  
  482.     for (i = 0 ; i < Dice->N_Vals ; i++) {
  483.         Graf_Number (Dice_Gr.T_Row,Dice_Gr.T_Col+(2*i)+2,
  484.                      Dice->Values[i],1,WHITE) ;
  485.     }
  486. }
  487.  
  488. /***************************************************************************/
  489.